{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "826IBSWMN4rr"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "ITj3u97-tNR7"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BYwfpc4wN4rt"
      },
      "source": [
        "# 가중치 클러스터링 종합 가이드"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IFva_Ed5N4ru"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/model_optimization/guide/clustering/clustering_comprehensive_guide\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">View on TensorFlow.org</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/model_optimization/guide/clustering/clustering_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Run in Google Colab</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/model_optimization/guide/clustering/clustering_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">View source on GitHub</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/model_optimization/guide/clustering/clustering_comprehensive_guide.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tidmcl3sN4rv"
      },
      "source": [
        "여기서는 TensorFlow 모델 최적화 도구 키트의 일부인 *가중치 클러스터링*에 대한 종합 가이드를 제공합니다.\n",
        "\n",
        "이 페이지는 다양한 사용 사례를 문서화하고 각각에 대해 API를 사용하는 방법을 보여줍니다. 필요한 API를 알고 나면, [API 문서](https://www.tensorflow.org/model_optimization/api_docs/python/tfmot/clustering)에서 매개변수와 하위 수준의 세부 정보를 찾아보세요.\n",
        "\n",
        "- 가중치 클러스터링의 이점과 지원되는 기능을 보려면 [개요](https://www.tensorflow.org/model_optimization/guide/clustering)를 참조하세요.\n",
        "- 단일 엔드 투 엔드 예는 [가중치 클러스터링 예](https://www.tensorflow.org/model_optimization/guide/clustering/clustering_example)를 참조하세요.\n",
        "\n",
        "이 가이드에서는 다음 사용 사례를 다룹니다.\n",
        "\n",
        "- 클러스터링된 모델을 정의합니다.\n",
        "- 클러스터링된 모델을 검사하고 역직렬화합니다.\n",
        "- 클러스터링된 모델의 정확성을 개선합니다.\n",
        "- 배포의 경우에만 압축의 이점을 확인하기 위한 단계를 취해야 합니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RRtKxbo8N4rv"
      },
      "source": [
        "## 설정\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "08dJRvOqN4rw"
      },
      "outputs": [],
      "source": [
        "! pip install -q tensorflow-model-optimization\n",
        "\n",
        "import tensorflow as tf\n",
        "import numpy as np\n",
        "import tempfile\n",
        "import os\n",
        "import tensorflow_model_optimization as tfmot\n",
        "\n",
        "input_dim = 20\n",
        "output_dim = 20\n",
        "x_train = np.random.randn(1, input_dim).astype(np.float32)\n",
        "y_train = tf.keras.utils.to_categorical(np.random.randn(1), num_classes=output_dim)\n",
        "\n",
        "def setup_model():\n",
        "  model = tf.keras.Sequential([\n",
        "      tf.keras.layers.Dense(input_dim, input_shape=[input_dim]),\n",
        "      tf.keras.layers.Flatten()\n",
        "  ])\n",
        "  return model\n",
        "\n",
        "def train_model(model):\n",
        "  model.compile(\n",
        "      loss=tf.keras.losses.categorical_crossentropy,\n",
        "      optimizer='adam',\n",
        "      metrics=['accuracy']\n",
        "  )\n",
        "  model.summary()\n",
        "  model.fit(x_train, y_train)\n",
        "  return model\n",
        "\n",
        "def save_model_weights(model):\n",
        "  _, pretrained_weights = tempfile.mkstemp('.h5')\n",
        "  model.save_weights(pretrained_weights)\n",
        "  return pretrained_weights\n",
        "\n",
        "def setup_pretrained_weights():\n",
        "  model= setup_model()\n",
        "  model = train_model(model)\n",
        "  pretrained_weights = save_model_weights(model)\n",
        "  return pretrained_weights\n",
        "\n",
        "def setup_pretrained_model():\n",
        "  model = setup_model()\n",
        "  pretrained_weights = setup_pretrained_weights()\n",
        "  model.load_weights(pretrained_weights)\n",
        "  return model\n",
        "\n",
        "def save_model_file(model):\n",
        "  _, keras_file = tempfile.mkstemp('.h5') \n",
        "  model.save(keras_file, include_optimizer=False)\n",
        "  return keras_file\n",
        "\n",
        "def get_gzipped_model_size(model):\n",
        "  # It returns the size of the gzipped model in bytes.\n",
        "  import os\n",
        "  import zipfile\n",
        "\n",
        "  keras_file = save_model_file(model)\n",
        "\n",
        "  _, zipped_file = tempfile.mkstemp('.zip')\n",
        "  with zipfile.ZipFile(zipped_file, 'w', compression=zipfile.ZIP_DEFLATED) as f:\n",
        "    f.write(keras_file)\n",
        "  return os.path.getsize(zipped_file)\n",
        "\n",
        "setup_model()\n",
        "pretrained_weights = setup_pretrained_weights()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ARd37qONN4rz"
      },
      "source": [
        "## 클러스터링된 모델 정의하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zHB3pkU3N4r0"
      },
      "source": [
        "### 전체 모델 클러스터링(순차적 및 함수형)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ig-il1lmN4r1"
      },
      "source": [
        "모델 정확성 개선을 위한 **팁**:\n",
        "\n",
        "- 이 API에 수용 가능한 정확성으로 미리 훈련된 모델을 전달해야 합니다. 클러스터링을 사용하여 처음부터 모델을 훈련하면 정확성이 떨어집니다.\n",
        "- 경우에 따라, 특정 레이어를 클러스터링하면 모델 정확성에 부정적인 영향을 미칩니다. 정확성에 가장 큰 영향을 미치는 레이어 클러스터링을 건너뛰는 방법을 보려면 \"일부 레이어 클러스터링\"을 확인하세요.\n",
        "\n",
        "모든 레이어를 클러스터링하려면 `tfmot.clustering.keras.cluster_weights`를 모델에 적용합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "29g7OADjN4r1"
      },
      "outputs": [],
      "source": [
        "import tensorflow_model_optimization as tfmot\n",
        "\n",
        "cluster_weights = tfmot.clustering.keras.cluster_weights\n",
        "CentroidInitialization = tfmot.clustering.keras.CentroidInitialization\n",
        "\n",
        "clustering_params = {\n",
        "  'number_of_clusters': 3,\n",
        "  'cluster_centroids_init': CentroidInitialization.DENSITY_BASED\n",
        "}\n",
        "\n",
        "model = setup_model()\n",
        "model.load_weights(pretrained_weights)\n",
        "\n",
        "clustered_model = cluster_weights(model, **clustering_params)\n",
        "\n",
        "clustered_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zEOHK4OON4r7"
      },
      "source": [
        "### 일부 레이어 클러스터링(순차적 및 기능적 모델)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ENscQ7ZWN4r8"
      },
      "source": [
        "모델 정확성 개선을 위한 **팁**:\n",
        "\n",
        "- You must pass a pre-trained model with acceptable accuracy to this API. Training models from scratch with clustering results in subpar accuracy.\n",
        "- 초기 레이어와 달리 더 많은 중복 매개변수(예: `tf.keras.layers.Dense`, `tf.keras.layers.Conv2D`)를 가진 이후 레이어를 클러스터링합니다.\n",
        "- 미세 조정 중 클러스터링된 레이어 이전에 초기 레이어를 고정합니다. 고정된 레이어의 수를 하이퍼 매개변수로 취급합니다. 경험적으로, 대부분의 초기 레이어를 고정하는 것이 현재의 클러스터링 API에 이상적입니다.\n",
        "- 중요 레이어(예: 주의 메커니즘)의 클러스터링을 피합니다.\n",
        "\n",
        "**추가 정보**: `tfmot.clustering.keras.cluster_weights` API 문서에서 레이어별로 클러스터링 구성을 변경하는 방법에 대한 세부 정보를 제공합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IqBdl3uJN4r_"
      },
      "outputs": [],
      "source": [
        "# Create a base model\n",
        "base_model = setup_model()\n",
        "base_model.load_weights(pretrained_weights)\n",
        "\n",
        "# Helper function uses `cluster_weights` to make only \n",
        "# the Dense layers train with clustering\n",
        "def apply_clustering_to_dense(layer):\n",
        "  if isinstance(layer, tf.keras.layers.Dense):\n",
        "    return cluster_weights(layer, **clustering_params)\n",
        "  return layer\n",
        "\n",
        "# Use `tf.keras.models.clone_model` to apply `apply_clustering_to_dense` \n",
        "# to the layers of the model.\n",
        "clustered_model = tf.keras.models.clone_model(\n",
        "    base_model,\n",
        "    clone_function=apply_clustering_to_dense,\n",
        ")\n",
        "\n",
        "clustered_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hN0DgpvD5Add"
      },
      "source": [
        "## 클러스터링된 모델 검사 및 역직렬화하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hfji5KWN6XCF"
      },
      "source": [
        "**사용 사례:** 이 코드는 HDF5 모델 형식에만 필요합니다(HDF5 가중치 또는 기타 형식은 해당되지 않음)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "w7P67mPk6RkQ"
      },
      "outputs": [],
      "source": [
        "# Define the model.\n",
        "base_model = setup_model()\n",
        "base_model.load_weights(pretrained_weights)\n",
        "clustered_model = cluster_weights(base_model, **clustering_params)\n",
        "\n",
        "# Save or checkpoint the model.\n",
        "_, keras_model_file = tempfile.mkstemp('.h5')\n",
        "clustered_model.save(keras_model_file, include_optimizer=True)\n",
        "\n",
        "# `cluster_scope` is needed for deserializing HDF5 models.\n",
        "with tfmot.clustering.keras.cluster_scope():\n",
        "  loaded_model = tf.keras.models.load_model(keras_model_file)\n",
        "\n",
        "loaded_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cUv-scK-N4sN"
      },
      "source": [
        "## 클러스터링된 모델의 정확성 개선하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-fZZopDBN4sO"
      },
      "source": [
        "특정 사용 사례에 대해 고려할 수 있는 팁을 소개합니다.\n",
        "\n",
        "- 중심 초기화는 최종 최적화된 모델의 정확성에 중요한 역할을 합니다. 일반적으로, 선형 초기화는 큰 가중치를 놓치지 않는 경향이 있으므로 밀도 및 임의 초기화보다 성능이 우수합니다. 그러나, 밀도 초기화는 바이모달 분포가 있는 가중치에 클러스터를 거의 사용하지 않는 경우 더 나은 정확성을 제공하는 것으로 관찰되었습니다.\n",
        "\n",
        "- 클러스터링된 모델을 미세 조정할 때 훈련에 사용되는 학습률보다 낮은 학습률을 설정합니다.\n",
        "\n",
        "- 모델 정확성을 개선하기 위한 일반적인 아이디어를 얻으려면 \"클러스터링된 모델 정의하기\"에서 사용 사례에 대한 팁을 살펴보세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4DXw7YbyN4sP"
      },
      "source": [
        "## 배포"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5Y5zLfPzN4sQ"
      },
      "source": [
        "### 크기 압축으로 모델 내보내기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wX4OrHD9N4sQ"
      },
      "source": [
        "**일반적인 실수**: 클러스터링의 압축 이점을 확인하려면 <code>strip_clustering</code>과 표준 압축 알고리즘(예: gzip 이용) 적용이 모두 필요합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZvuiCBsVN4sR"
      },
      "outputs": [],
      "source": [
        "model = setup_model()\n",
        "clustered_model = cluster_weights(model, **clustering_params)\n",
        "\n",
        "clustered_model.compile(\n",
        "    loss=tf.keras.losses.categorical_crossentropy,\n",
        "    optimizer='adam',\n",
        "    metrics=['accuracy']\n",
        ")\n",
        "\n",
        "clustered_model.fit(\n",
        "    x_train,\n",
        "    y_train\n",
        ")\n",
        "\n",
        "final_model = tfmot.clustering.keras.strip_clustering(clustered_model)\n",
        "\n",
        "print(\"final model\")\n",
        "final_model.summary()\n",
        "\n",
        "print(\"\\n\")\n",
        "print(\"Size of gzipped clustered model without stripping: %.2f bytes\" \n",
        "      % (get_gzipped_model_size(clustered_model)))\n",
        "print(\"Size of gzipped clustered model with stripping: %.2f bytes\" \n",
        "      % (get_gzipped_model_size(final_model)))"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "clustering_comprehensive_guide.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
